package handler

import (
	"net/http"
	"strings"
	"encoding/json"
	"fmt"
	"go-scripts/common"
	"errors"
	"time"
)

var logger *common.Log = common.GetLogger()

type AppHandler struct {
	routes map[string]func(a *Global)
	routesTrie *common.Trie
}

type Route interface {
	GetRoute()map[string]func(app *Global)
}

//整个app的最外层
func NewApp(routes Route) *AppHandler {
	app := new(AppHandler)
	//初始化路由
	rs := routes.GetRoute()
	//初始化路由字典树，用来匹配通配符
	trie := common.NewTrie()
	for key, _ := range rs {
		pathEachStr := strings.Split(key, "/")[1:]
		trie.InsertStr(pathEachStr)
	}
	app.routes = rs
	app.routesTrie = trie
	return app
}

//处理所有请求
func (a *AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)  {
	defer func() {
		if e := recover(); e != nil {
			fmt.Println(e)
		}
	}()
	//将http request response 注入
	global := NewGlobal(w, r)

	//打印所有请求并返回path
	path := printURLMiddleWare(r)
	form := r.Form
	params, err := json.Marshal(form)
	if err != nil {
		logger.Error(err)
	}
	logger.Info(fmt.Sprintf("%s params: %s", path, params))
	begin := time.Now().UnixNano()
	//判断请求是否存在
	if handleFunc, exsist:= a.routes[a.matchUrl(path)]; exsist {
		//处理请求
		handleFunc(global)
		logger.Info(path, (time.Now().UnixNano() - begin) / 1000000, "ms")
	} else {
		//拒绝请求
		logger.Error(path, 404)

		global.NewError(404, errors.New("page not found"))
	}
}

//匹配访问的url
func (a *AppHandler) matchUrl(url string) string {
	methodAndpath := strings.Split(url, " ")
	eachRest := strings.Split(methodAndpath[1], "/")[1:]
	root := a.routesTrie.GetRoot()
	return methodAndpath[0] + " " + matchStrings(root, eachRest, 0, "")
}
//迭代url的每一块，进行匹配
func matchStrings(node *common.TreeNode, eachRest[] string, index int, path string) string {
	if len(eachRest) == index {
		if node.IsEnd() {
			return path
		} else {
			return ""
		}
	}
	rest := eachRest[index]
	sonNode := node.GetSon()[rest]
	if sonNode != nil {
		index++
		return matchStrings(sonNode, eachRest, index, path + "/" + rest)
	}
	sonNode = node.GetSon()["*"]
	if sonNode != nil {
		if sonNode.IsEnd() {
			return path + "/*"
		}
		index++
		return matchStrings(sonNode, eachRest, index, path + "/*")
	}
	return ""
}
//打印url中间件
func printURLMiddleWare(r *http.Request) string {
	//获取method
	method := r.Method
	//获取path
	url := r.URL.Path
	if err := r.ParseForm(); err != nil {
		logger.Error(err)
	}
	return fmt.Sprintf("%s %s", method, url)
}

